package de.fh.ffm.elevator;

/**
 * Elevator used by Persons to get from one Floor to another
 * 
 * @author harscher <swe.chr@googlemail.com>
 * @author mann <mann.mario@googlemail.com>
 * 
 */
public class Elevator {

	/**
	 * Doors on Elevators
	 * 
	 * @author mann <mann.mario@googlemail.com>
	 */
	private static class ElevatorDoor extends Door {

		/**
		 * the Elevator this Door is in
		 */
		private final Elevator elevator;

		/**
		 * Creates an ElevatorDoor with the corresponding Floor
		 * 
		 * @param elevator
		 */
		public ElevatorDoor ( final Elevator elevator ) {
			this.elevator = elevator;
		}

		/**
		 * check if the door can be opened
		 * 
		 * @return true if the elevator is on the floor who wants to open the
		 *         door; false otherwise
		 */
		public boolean canBeOpened () {
			return null != elevator.getFloor();
		}

	}

	/**
	 * Buttons on Elevators
	 */
	private static class ElevatorButton extends Button {

		/**
		 * the Elevator this Door is in
		 */
		private final Elevator elevator;

		/**
		 * Creates an ElevatorButton
		 * 
		 * @param elevator
		 */
		public ElevatorButton ( final Elevator elevator ) {
			this.elevator = elevator;
		}

		/**
		 * When pushing the ElevatorButton the elevator is called to the floor
		 * it's currently not on.
		 *
		 * @param elevator
		 */
		@Override
		public void onPush () {
			Floor destFloor = getElevatorManager().getOtherFloorForElevator(
					elevator);
			getElevatorManager().callElevatorToFloor(destFloor);
			destFloor.getButton().activate();
		}
	}

	/**
	 * Is thrown when a Person tries to enter a full Elevator
	 * 
	 * @author Mann
	 */
	public static class IsFullException extends RuntimeException {
		private static final long serialVersionUID = 1L;
	}

	/**
	 * button for switching the Floor
	 */
	private Button button = new ElevatorButton(this);

	/**
	 * A Person in the elevator
	 * 
	 * null means no Person present
	 */
	private Person person;

	/**
	 * door of the elevator
	 */
	private Door door = new ElevatorDoor(this);

	/**
	 * floor where the elevator is at this moment
	 * 
	 * null means Elevator is on no floor (in transition)
	 */
	private Floor floor;

	public Floor getFloor () {
		return this.floor;
	}

	/**
	 * get the elevator door
	 * 
	 * @return door
	 */
	public Door getDoor () {
		return door;
	}

	/**
	 * Signals the elevator that it has arrived on a Floor
	 * 
	 * @param floor
	 *            , the Floor it has arrived on
	 */
	public void arrivesAtFloor ( Floor f ) {
		floor = f;
		f.elevatorArrived(this);

		door.open();
		f.getDoor().open();

		getButton().deactivate();
		f.getButton().deactivate();

	}

	/**
	 * check if a Person can enter the elevator
	 * 
	 * @return true if one Person can enter; false otherwise;
	 */
	public boolean canPersonEnter () {
		return null == person;
	}

	/**
	 * a Person entered the elevator
	 * 
	 * @param person
	 */
	public void personEntered ( Person person ) {
		this.person = person;
	}

	/**
	 * a person left the elevator
	 * 
	 * @param person
	 */
	public void personLeft ( Person person ) {
		this.person = null;
	}

	/**
	 * Button of the elevator object
	 * 
	 * @return button belonging to the elevator;
	 */
	public Button getButton () {
		return button;
	}

	/**
	 * the elevator starts moving.
	 * Closes doors on the floor and elevator and sets its floor to null
	 * 
	 */
	public void leavesFloor () {
		floor.elevatorLeft(this);
		getDoor().close();
		floor.getDoor().close();
		floor = null;
	}

	/**
	 * check if the elevator is on a floor
	 * 
	 * @return floor if elevator is on a floor; null otherwise;
	 */
	public boolean isOnFloor () {
		return null != floor;
	}

}
